{-# OPTIONS_GHC -Wall -Werror -fno-warn-orphans #-}
{-# LANGUAGE FlexibleContexts, TypeFamilies, TypeSynonymInstances,
  FlexibleInstances, MultiParamTypeClasses #-}

module Point2D where

import Math
import Vector2D
import Projectable
import Data.VectorSpace hiding (Scalar)
import Data.AffineSpace
import Control.Parallel.Strategies

newtype Point2 = P2 { unP2 :: Vector2 } deriving Eq

instance Show Point2 where
  show (P2 (V2 x y)) = "["++showN x++","++showN y++"]"

inP2 :: (Vector2 -> Vector2) -> Point2 -> Point2
inP2 f = P2 . f . unP2

-- | Construct a 2D point
point2 :: Scalar -> Scalar -> Point2
point2 x y = P2 (vector2 x y)
{-# INLINE point2 #-} 

-- | To convert a point to a vector, subtract (.-.) the origin from it.
-- | To convert a vector to a point, add (.+^) the origin to it.
origin2 :: Point2
origin2 = point2 0 0
{-# INLINE origin2 #-} 

instance Project2 Point2 where
  project2 = project2 . unP2
  compose2 = P2 . compose2

instance ProjectX Point2 where
  getX = getX . unP2
  mapX = inP2 . mapX

instance ProjectY Point2 where
  getY = getY . unP2
  mapY = inP2 . mapY

instance AffineSpace Point2 where
  type Diff Point2 = Vector2
  P2 v1 .-. P2 v2 = v1 ^-^ v2
  P2 v1 .+^ v2 = P2 (v1 ^+^ v2)

instance NFData (Point2)
